#include "pch.h"
#include "CppUnitTest.h"
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>


#include "../Node.h"
#include "../Graph.h"
#include "../Solution.h"
#include "../core.h"
#include "../Node.cpp"
#include "../Graph.cpp"
#include "../Solution.cpp"
#include "../core.cpp"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;

namespace UnitTest
{
	TEST_CLASS(UnitTest)
	{
	public:

		TEST_METHOD(TestMethod0) {
			Assert::AreEqual(3, Add(1, 2));
		}
		
		TEST_METHOD(TestMethod1) {
		    int len = 4;
		    char *words[] = {"woo", "oom", "moon", "noox"};
		    int ret = 6;
		    char *result[] = {
		            "woo oom",
		            "moon noox",
		            "oom moon",
		            "woo oom moon",
		            "oom moon noox",
                    "woo oom moon noox"
		    };
		    char *_result_buf = (char *) malloc(0x1000);
		    char **_result = (char **) malloc (sizeof (char *) * 100);
		    _result[0] = _result_buf;
		    int _num = gen_chains_all(words, len, _result);
		    Assert::AreEqual(ret, _num);
		    vector<string> ans_vec, ret_vec;
		    for (int i = 0; i < ret; i++) {
		        ans_vec.emplace_back(result[i]);
		        ret_vec.emplace_back(_result[i]);
		    }
		    sort(ans_vec.begin(), ans_vec.end());
		    sort(ret_vec.begin(), ret_vec.end());
		    for (int i = 0; i < ret; i++) {
		        Assert::AreEqual(ans_vec[i], ret_vec[i]);
		    }
		}

		TEST_METHOD(TestMethod2) {
			int len = 3;
			char* words[] = { "ab", "xyz", "ba"};
			int ret = CORE_ERROR_ILLEGAL_CIRCLE;
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			try {
				int _num = gen_chains_all(words, len, _result);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "There is a circle in the chain.");
			}
			
		}

		TEST_METHOD(TestMethod3) {
		    int len = 11;
		    int head = 0, tail = 0;
		    bool circ = 0;
		    char *words[] = {
		            "algebra",
		            "apple",
		            "zoo",
		            "elephant",
		            "under",
		            "fox",
		            "dog",
		            "moon",
		            "leaf",
		            "trick",
                    "pseudopseudohypoparathyroidism"
		    };
		    int ret = 4;
		    char *result[] = {
		            "algebra",
		            "apple",
		            "elephant",
                    "trick"
		    };
		    char *_result_buf = (char *) malloc(0x1000);
		    char **_result = (char **) malloc (sizeof (char *) * 100);
		    _result[0] = _result_buf;
		    int _num = gen_chain_word(words, len, _result, head, tail, circ);
		    Assert::AreEqual(ret, _num);
		    vector<string> ans_vec, ret_vec;
		    for (int i = 0; i < ret; i++) {
		        ans_vec.emplace_back(result[i]);
		        ret_vec.emplace_back(_result[i]);
		    }
		    for (int i = 0; i < ret; i++) {
		        Assert::AreEqual(ans_vec[i], ret_vec[i]);
		    }
		}

		TEST_METHOD(TestMethod4) {
			int len = 11;
			int head = 'l', tail = 0;
			bool circ = 0;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"pseudopseudohypoparathyroidism"
			};
			int ret = 2;
			char* result[] = {
					"leaf",
					"fox"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_word(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod5) {
			int len = 11;
			int head = 0, tail = 0;
			bool circ = true;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"kkd"
			};
			int ret = 6;
			char* result[] = {
					"algebra",
					"apple",
					"elephant",
					"trick",
					"kkd",
					"dog"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_word(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod6) {
			int len = 11;
			int head = 0, tail = 0;
			bool circ = false;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"pseudopseudohypoparathyroidism"
			};
			int ret = 3;
			char* result[] = {
					"apple",
					"elephant",
					"trick"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_word_unique(words, len, _result);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod7) {
		    int len = 3;
		    char* words[] = { "ab", "xyz", "ba"};
		    int ret = CORE_ERROR_ILLEGAL_CIRCLE;
		    char* _result_buf = (char*)malloc(0x1000);
		    char** _result = (char**)malloc(sizeof(char*) * 100);
		    _result[0] = _result_buf;
			try {
				int _num = gen_chain_word_unique(words, len, _result);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "There is a circle in the chain.");
			}
		    
		}

		TEST_METHOD(TestMethod8) {
			int len = 11;
			int head = 0, tail = 0;
			bool circ = false;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"pseudopseudohypoparathyroidism"
			};
			int ret = 2;
			char* result[] = {
					"pseudopseudohypoparathyroidism",
					"moon"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_char(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod9) {
			int len = 11;
			int head = 'a', tail = 0;
			bool circ = false;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"pseudopseudohypoparathyroidism"
			};
			int ret = 4;
			char* result[] = {
					"algebra",
					"apple",
					"elephant",
					"trick"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_char(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}


		TEST_METHOD(TestMethod10) {
			int len = 11;
			int head = 0, tail = 'a';
			bool circ = false;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"pseudopseudohypoparathyroidism"
			};
			int ret = 1;
			char* result[] = {
					"algebra"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_char(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod11) {
			int len = 11;
			int head = 0, tail = 0;
			bool circ = true;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"kseudopseudohypoparathyroidisa"
			};
			int ret = 5;
			char* result[] = {
					"kseudopseudohypoparathyroidisa",
					"algebra",
					"apple",
					"elephant",
					"trick"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_char(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}

		TEST_METHOD(TestMethod12) {
			int len = 3;
			char* words[] = { "ab", "xyz", "ba" };
			int ret = CORE_ERROR_ILLEGAL_CIRCLE;
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			try {
				int _num = gen_chain_word(words, len, _result, 0, 0, false);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "There is a circle in the chain.");
			}

			
			
		}

		TEST_METHOD(TestMethod13) {
			int len = 3;
			char* words[] = { "ab", "xyz", "ba" };
			int ret = CORE_ERROR_ILLEGAL_CIRCLE;
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			try {
				int _num = gen_chain_char(words, len, _result, 0, 0, false);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "There is a circle in the chain.");
			}
			
		}



		TEST_METHOD(TestMethod14) {
			int len = 11;
			int head = 'k', tail = 0;
			bool circ = true;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"kseudopseudohypoparathyroidisa"
			};
			int ret = 5;
			char* result[] = {
					"kseudopseudohypoparathyroidisa",
					"algebra",
					"apple",
					"elephant",
					"trick"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_char(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}



		TEST_METHOD(TestMethod15) {
			int len = 11;
			int head = 'a', tail = 0;
			bool circ = true;
			char* words[] = {
					"algebra",
					"apple",
					"zoo",
					"elephant",
					"under",
					"fox",
					"dog",
					"moon",
					"leaf",
					"trick",
					"kkd"
			};
			int ret = 6;
			char* result[] = {
					"algebra",
					"apple",
					"elephant",
					"trick",
					"kkd",
					"dog"
			};
			char* _result_buf = (char*)malloc(0x1000);
			char** _result = (char**)malloc(sizeof(char*) * 100);
			_result[0] = _result_buf;
			int _num = gen_chain_word(words, len, _result, head, tail, circ);
			Assert::AreEqual(ret, _num);
			vector<string> ans_vec, ret_vec;
			for (int i = 0; i < ret; i++) {
				ans_vec.emplace_back(result[i]);
				ret_vec.emplace_back(_result[i]);
			}
			for (int i = 0; i < ret; i++) {
				Assert::AreEqual(ans_vec[i], ret_vec[i]);
			}
		}


        TEST_METHOD(TestMethod16) {
            int len = 11;
            int head = '-', tail = 0;
            bool circ = true;
            char* words[] = {
                    "algebra",
                    "apple",
                    "zoo",
                    "elephant",
                    "under",
                    "fox",
                    "dog",
                    "moon",
                    "leaf",
                    "trick",
                    "kkd"
            };
            int ret = 6;
            char* result[] = {
                    "algebra",
                    "apple",
                    "elephant",
                    "trick",
                    "kkd",
                    "dog"
            };
            char* _result_buf = (char*)malloc(0x1000);
            char** _result = (char**)malloc(sizeof(char*) * 100);
            _result[0] = _result_buf;
			try {
				int _num = gen_chain_word(words, len, _result, head, tail, circ);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(),"Head is not a single letter." );
			}
            
            

        }


        TEST_METHOD(TestMethod17) {
            int len = 11;
            int head = 'k', tail = '=';
            bool circ = true;
            char* words[] = {
                    "algebra",
                    "apple",
                    "zoo",
                    "elephant",
                    "under",
                    "fox",
                    "dog",
                    "moon",
                    "leaf",
                    "trick",
                    "kseudopseudohypoparathyroidisa"
            };
            int ret = 5;
            char* result[] = {
                    "kseudopseudohypoparathyroidisa",
                    "algebra",
                    "apple",
                    "elephant",
                    "trick"
            };
            char* _result_buf = (char*)malloc(0x1000);
            char** _result = (char**)malloc(sizeof(char*) * 100);
            _result[0] = _result_buf;
			try {
				int _num = gen_chain_char(words, len, _result, head, tail, circ);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "Tail is not a single letter.");
			}
            

        }


        TEST_METHOD(TestMethod18) {
            int len = 4;
            char *words[] = {"woo", "oom", "moon", "noox"};
            int ret = 6;
            char *result[] = {
                    "woo oom",
                    "moon noox",
                    "oom moon",
                    "woo oom moon",
                    "oom moon noox",
                    "woo oom moon noox"
            };
            char *_result_buf = (char *) malloc(0x1000);
            char **_result = (char **) malloc (sizeof (char *) * 100);
            _result[0] = _result_buf;
			try {
				int _num = gen_chains_all(words, -1, _result);
			}
			catch (exception& e) {
				Assert::AreEqual(e.what(), "len should be large than 0.");
			}
            


        }
	};
}
